unit uLogManager_Impl;

interface

uses
  Classes, SysUtils, Windows, Forms, uLogManager_Intf, uIntfObject_Impl;

type
  TLog = class;
  TLogManager = class;
  TLogStorer = class;
  TTXTLogStorer = class;
  TLog = class(TCollectionItem)
  private
    FLogLevel: TLogLevel;
    FLogMessage: string;
    FTimestamp: TDateTime;
  public
    constructor Create(Collection: TCollection); override;
  published
    property LogLevel: TLogLevel read FLogLevel write FLogLevel;
    property LogMessage: string read FLogMessage write FLogMessage;
    property Timestamp: TDateTime read FTimestamp write FTimestamp;
  end;

  TLogManager = class(TCollection, ILogManager)
  private
    FBeLogLevel: TLogLevel;
    FLogStorer: ILogStorer;
    function GetLog(Index: Integer): TLog;
    procedure SetLogs(Index: Integer; Value: TLog);
  protected
    FRefCount: Integer;
    function Add: TLog;
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    property Items;
  public
    destructor Destroy; override;
    procedure Log(ALogMessage: string; ALogLevel: TLogLevel = llDebug);
    property BeLogLevel: TLogLevel read FBeLogLevel write FBeLogLevel default
        llDebug;
    property Logs[Index: Integer]: TLog read GetLog write SetLogs; default;
    property LogStorer: ILogStorer read FLogStorer write FLogStorer;
  end;

  TLogStorer = class(TIntfObject, ILogStorer)
  public
    procedure SaveLog(ALogMessage: string); virtual; stdcall; abstract;
  end;

  TTXTLogStorer = class(TLogStorer)
  private
    FFileName: string;
    FStorer: TextFile;
  public
    constructor Create;
    destructor Destroy; override;
    procedure SaveLog(ALogMessage: string); override; stdcall;
  end;

implementation

var
  Buff: array[1..262144] of Char;

{ TLogManager }

{
************************************* TLog *************************************
}
constructor TLog.Create(Collection: TCollection);
begin
  inherited Create(Collection);
  FTimeStamp:= Now;
end;

{
********************************* TLogManager **********************************
}
destructor TLogManager.Destroy;
begin
  FLogStorer:= nil;
  inherited;
end;

function TLogManager.Add: TLog;
begin
  Result:= TLog(inherited Add);
end;

function TLogManager.GetLog(Index: Integer): TLog;
begin
  Result:= TLog(Items[Index]);
end;

procedure TLogManager.Log(ALogMessage: string; ALogLevel: TLogLevel = llDebug);
var
  aMessage: string;
begin
  with Add do
  begin
    LogMessage:= ALogMessage;
    LogLevel:= ALogLevel;
    if LogLevel >= BeLogLevel then
    aMessage:= Format('%s#[%s] - %s', [FormatDateTime('yyyy-mm-dd hh:nn:ss', Timestamp), LogLevelArray[Ord(LogLevel)], LogMessage]);
    LogStorer.SaveLog(aMessage);
  end;
end;

function TLogManager.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := 0
  else
    Result := E_NOINTERFACE;
end;

procedure TLogManager.SetLogs(Index: Integer; Value: TLog);
begin
  Items[Index]:= Value;
end;

function TLogManager._AddRef: Integer;
begin
  Result := InterlockedIncrement(FRefCount);
end;

function TLogManager._Release: Integer;
begin
  Result := InterlockedDecrement(FRefCount);
  //  if Result = 0 then
  //    Destroy;
end;

{
******************************** TTXTLogStorer *********************************
}
constructor TTXTLogStorer.Create;
begin
  FFileName:= Format('%sLogs\%s_Log.txt', [ExtractFilePath(Application.ExeName), FormatDateTime('yyyymmddhhnnss', Now)]);
  AssignFile(FStorer, FFileName);

  SetTextBuf(FStorer, Buff, SizeOf(Buff));
end;

destructor TTXTLogStorer.Destroy;
begin
  CloseFile(FStorer);
  inherited;
end;

procedure TTXTLogStorer.SaveLog(ALogMessage: string);
begin
  if FileExists(FFileName) then
    Append(FStorer)
  else
    Rewrite(FStorer);

  Writeln(FStorer, ALogMessage);
  Flush(FStorer);
end;

end.
